﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Windows;
using VMWorkshop.Domain;

namespace VMWorkshop.Silverlight.Models.ViewModels
{
    public class DemoViewModel : INotifyPropertyChanged
    {
        // Events
        public event PropertyChangedEventHandler PropertyChanged;

        // Private Fields
        private Uri _listServiceLocation = null;
        private Uri _editServiceLocation = null;
        private Uri _persistLocation = null;
        private Visibility _updateMessageVisibility = Visibility.Collapsed;
        private Visibility _editFormVisibility = Visibility.Collapsed;
        private Visibility _productsGridVisibility = Visibility.Collapsed;
        private ProductEditView _selectedProduct = new ProductEditView();
        private WebClient _client = null;
        private IEnumerable<ProductListView> _products = null;
        
        // Public Properties
        public ProductEditView SelectedProduct 
        {
            get { return this._selectedProduct; }
            set
            {
                if (this._selectedProduct != value)
                {
                    this._selectedProduct = value;
                    this.RaisePropertyChangedEvent("SelectedProduct");
                }
            }
        }

        public IEnumerable<ProductListView> Products
        {
            get { return this._products; }
            set 
            {
                if (this._products != value)
                {
                    this._products = value;
                    this.RaisePropertyChangedEvent("Products");
                }
            }
        }

        public Uri ListServiceLocation
        {
            get { return this._listServiceLocation; }
        }

        public Uri EditServiceLocation
        {
            get { return this._editServiceLocation; }
        }

        public Visibility UpdateMessageVisibility
        {
            get { return this._updateMessageVisibility; }
            set
            {
                if (this._updateMessageVisibility != value)
                {
                    this._updateMessageVisibility = value;
                    this.RaisePropertyChangedEvent("UpdateMessageVisibility");
                }
            }
        }

        public Visibility EditFormVisibility
        {
            get { return this._editFormVisibility; }
            set
            {
                if (this._editFormVisibility != value)
                {
                    this._editFormVisibility = value;
                    this.RaisePropertyChangedEvent("EditFormVisibility");
                }
            }
        }

        public Visibility ProductsGridVisibility
        {
            get { return this._productsGridVisibility; }
            set
            {
                if (this._productsGridVisibility != value)
                {
                    this._productsGridVisibility = value;
                    this.RaisePropertyChangedEvent("ProductsGridVisibility");
                }
            }
        }

        // Constructor
        public DemoViewModel(Uri listServiceLocation, Uri editServiceLocation, Uri persistLocation)
        {
            this._listServiceLocation = listServiceLocation;
            this._editServiceLocation = editServiceLocation;
            this._persistLocation = persistLocation;

            this._client = new WebClient();
            this.SetAcceptHeader();
            
            this.SelectedProduct = new ProductEditView();
        }

        // Public interface methods and callbacks
        public void GetProducts()
        {
            if (!this._client.IsBusy)
            {
                this.ClearOpenReadCompletedEvents();
                this._client.OpenReadCompleted += new OpenReadCompletedEventHandler(this.GetProductsCompleted);
                this._client.OpenReadAsync(this._listServiceLocation);
            }
        }

        private void GetProductsCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            this.Products = this.ParseJsonList<ProductListView>(e.Result);
            this.ProductsGridVisibility = Visibility.Visible;
        }

        public void GetSelectedProduct(int productId)
        {
            if (!this._client.IsBusy)
            {
                this.ClearOpenReadCompletedEvents();
                this._client.OpenReadCompleted += new OpenReadCompletedEventHandler(GetSelectedProductCompleted);
                this.SetAcceptHeader();

                string uri = this._editServiceLocation.OriginalString + string.Format("/{0}", productId);
                UriKind kind = this._editServiceLocation.IsAbsoluteUri ? UriKind.Absolute : UriKind.Relative;
                this._client.OpenReadAsync(new Uri(uri, kind));

                this.UpdateMessageVisibility = Visibility.Collapsed;
            }
        }

        private void GetSelectedProductCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            this.SelectedProduct = this.ParseJsonSingle<ProductEditView>(e.Result);
            this.EditFormVisibility = Visibility.Visible;
        }

        public void Persist()
        {
            WebClientPost post = new WebClientPost(this._persistLocation);
            post.PostComplete += new EventHandler(PersistCompleted);
            post.AddDataItem(this.SelectedProduct);
            post.Send();
        }

        private void PersistCompleted(object sender, EventArgs e)
        {
            this.EditFormVisibility = Visibility.Collapsed;
            this.UpdateMessageVisibility = Visibility.Visible;
        }

        // Utility Methods
        protected virtual void RaisePropertyChangedEvent(params string[] propertyNames)
        {
            if (this.PropertyChanged != null)
            {
                foreach (string name in propertyNames)
                {
                    this.PropertyChanged(this, new PropertyChangedEventArgs(name));
                }
            }
        }

        private void SetAcceptHeader()
        {
            this._client.Headers[HttpRequestHeader.Accept] = RequestHeaders.Json;
        }

        private void ClearOpenReadCompletedEvents()
        {
            this._client.OpenReadCompleted -= new OpenReadCompletedEventHandler(this.GetProductsCompleted);
            this._client.OpenReadCompleted -= new OpenReadCompletedEventHandler(this.GetSelectedProductCompleted);
        }

        private IEnumerable<T> ParseJsonList<T>(Stream stream)
        {
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T[]));
            T[] result = (T[])serializer.ReadObject(stream);
            return result;
        }

        private T ParseJsonSingle<T>(Stream stream)
        {
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
            T result = (T)serializer.ReadObject(stream);
            return result;
        }
    }
}
